home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / expanded.lha / expanded / src / Map.C < prev    next >
C/C++ Source or Header  |  1992-03-19  |  51KB  |  1,794 lines

  1. //
  2. // Linear-Affine-Projective Geometry Package
  3. //
  4. // Map.C
  5. //
  6. // $Header$
  7. //
  8. // William J.R. Longabaugh 
  9. // University of Washington
  10. //
  11. // Implementation of the linear-affine-projective geometry
  12. // package described in William J.R. Longabaugh, "An Expanded
  13. // System for Coordinate-Free Geometric Programming", Master's 
  14. // thesis, University of Washington, 1992.
  15. //
  16. // Copyright (c) 1992, William J.R. Longabaugh
  17. //   Copying, use and development for non-commercial purposes permitted.
  18. //   All rights for commercial use reserved.
  19. //   This software is unsupported and without warranty; it is
  20. //   provided "as is".
  21. //
  22. // ***********************************************************************
  23.  
  24. #include <math.h>
  25. #include "Lap.h"
  26.  
  27. // ***********************************************************************
  28. // ***********************************************************************
  29. //
  30. // Map Class
  31. //
  32. // ***********************************************************************
  33. // ***********************************************************************
  34. //
  35. // Private/protected member functions
  36. //
  37. // ***********************************************************************
  38. //
  39. // This routine is used by map constructors to convert lists
  40. // of arbitrary geometric objects into objects of the desired type
  41. // in the desired space.  A matrix containing std. coords of the
  42. // objects is built:
  43. //
  44.  
  45. Boolean Map::ConvertList(GeObList& v, GeObType targ,
  46.              SubSet& dest, Matrix* temp)
  47. {
  48.   Space destspace = dest.EmbeddingSpace();
  49.  
  50. // Determine if the matrix reps. need to be normalized:
  51.  
  52.   Boolean norm = 
  53.     ((destspace.Holds() == PROJ_SPACE) && (dest.Holds() == AFFINE_SUBSET));
  54.  
  55.   for (int i = 0; i < v.Length(); i++) {
  56.     GeOb tempgeob = v[i].MapTo(targ);
  57.     if (tempgeob.SpaceOf() != destspace) {
  58.       return (FALSE);
  59.     } 
  60.     if (!dest.IsIn(tempgeob)) {
  61.       return (FALSE);
  62.     }
  63.     if (norm) {
  64.       tempgeob = dest.Normalize(tempgeob);
  65.     }
  66.     (*temp)[i] = tempgeob.MatrixRep()[0];
  67.   }
  68.   return (TRUE);
  69. }
  70.  
  71. // ***********************************************************************
  72. //
  73. // Apply associated linear map (without explicitly building it):
  74. //
  75.  
  76. GeOb Map::ApplyAL(GeOb& v)
  77. {
  78.   static char* sig = "GeOb Map::ApplyAL(void)";
  79.  
  80.   GeOb temp = v.MapTo(AFF_VECTOR);
  81.   if (temp.SpaceOf() != domain.TangentSub().EmbeddingSpace()) {
  82.     errh.ErrorExit(sig, "Object cannot be mapped to domain space", *this, v);
  83.   } 
  84.   if (!domain.TangentSub().IsIn(temp)) {
  85.     errh.ErrorExit(sig, "Mapped object not in specified domain subset",
  86.                    *this, temp);
  87.   }
  88.  
  89. // The range depends on the character of the affine map.  If it is
  90. // to an affine subset of an affine space, the range is the
  91. // corresponding subspace of the tangent space.  If it is to an
  92. // affine subset of a vector space, the range is a parallel vector
  93. // subspace of the vector space.  If it is to a vector subset,
  94. // this range is the same vector subset.
  95.  
  96.   if (range.EmbeddingSpace().Holds() == AFF_SPACE) {
  97.     Matrix alt = temp.MatrixRep() *
  98.              domain.EmbeddingSpace().HoistTangent() * t;
  99.     Matrix holdmatr = range.EmbeddingSpace().HoistTangent();
  100.     GeOb retval(AFF_VECTOR, range.TangentSub().EmbeddingSpace(),
  101.             alt * Transpose(holdmatr));
  102.     return retval;  
  103.   } else {
  104.     Matrix alt = temp.MatrixRep() *
  105.              domain.EmbeddingSpace().HoistTangent() * t;
  106.     GeOb retval(VECTOR, range.EmbeddingSpace(), alt);
  107.     return retval;  
  108.   }
  109. }
  110.  
  111. // ***********************************************************************
  112. //
  113. // Given all the information, builds a new Map
  114. //
  115.  
  116. Map::Map(MapType ty, Boolean i, SubSet& r,
  117.      SubSet& d, Matrix& tm, Matrix& it, Boolean isdf,
  118.      Boolean hal, GeObType dt, GeObType rt) :  range(r), domain(d),
  119.                                t(tm), invt(it)
  120. {
  121.   invertible = i;
  122.   type = ANY_MAP;
  123.   holds = ty;
  124.   hasAL = hal;
  125.   isDefault = isdf;
  126.   domtype = dt;
  127.   rettype = rt;
  128. }
  129.  
  130. // ***********************************************************************
  131. //
  132. // Dumps out all the data for a map:
  133. //
  134.  
  135. void Map::data_out(ostream& c, int indent, char* name) 
  136. {
  137.   char *ibloc = new char[indent + 1];
  138.   for (int i = 0; i < indent; i++) {
  139.     *(ibloc + i) = ' ';
  140.   }
  141.   *(ibloc + indent) = '\0';
  142.  
  143.   c << ibloc << ast;
  144.   c << ibloc << name;
  145.   c << ibloc << "Type of map: ";
  146.   MapTypeOut(c, type);
  147.   c << "\n";
  148.   c << ibloc << "Currently holds: ";
  149.   MapTypeOut(c, holds);
  150.   c << "\n";
  151.   if (holds != NULL_MAP) { 
  152.     c << ibloc << "Domain subset:\n";
  153.     domain.debug_out(c, indent + ERR_IND);
  154.     c << ibloc << "Range subset:\n";
  155.     range.debug_out(c, indent + ERR_IND);
  156.     c << ibloc << "Matrix representation of map:\n";
  157.     t.debug_out(c, indent + ERR_IND);
  158.     c << ibloc << "Type of domain argument: ";
  159.     GeObTypeOut(c, domtype);
  160.     c << "\n" << ibloc << "Type of result: ";
  161.     GeObTypeOut(c, rettype);
  162.     if (invertible) { 
  163.       c << "\n" << ibloc << "Matrix representation of inverse:\n";
  164.       invt.debug_out(c, indent + ERR_IND);
  165.     } else {
  166.       c << "\n" << ibloc << "Map is not invertible\n";
  167.     }  
  168.     if (hasAL) { 
  169.       c << ibloc << "Map has an associated linear map\n";
  170.     } else {
  171.       c << ibloc << "Map does not have an associated linear map\n";
  172.     }
  173.     if (isDefault) { 
  174.       c << ibloc << "Map is a default map\n";
  175.     } else {
  176.       c << ibloc << "Map is not a default map\n";
  177.     }
  178.   }  
  179.   c << ibloc << ast;
  180.  
  181.   delete ibloc;
  182.   return;
  183. }
  184.  
  185. // ***********************************************************************
  186. //
  187. // Public member functions
  188. //
  189. // ***********************************************************************
  190. //
  191. // Need to do memberwise initialization, since matrix class members need
  192. // to do memberwise initialization:
  193. //
  194.  
  195. Map::Map(Map &m) : range(m.range), domain(m.domain), t(m.t), invt(m.invt)
  196. {
  197.   invertible = m.invertible;
  198.   type = ANY_MAP;
  199.   holds = m.holds;
  200.   hasAL = m.hasAL;
  201.   isDefault = m.isDefault;
  202.   domtype = m.domtype;
  203.   rettype = m.rettype;
  204. }
  205.  
  206. // ***********************************************************************
  207. //
  208. // Need to do memberwise assignment, since Matrix class members need to
  209. // do memberwise assignment:
  210. //
  211.  
  212. Map& Map::operator=(Map &m)
  213. {
  214. //
  215. // This weird checking is required to bypass the apparent inheritance of
  216. // assignment under g++ 1.37:
  217. //
  218.   if ((type != ANY_MAP) && (type != m.holds) && (m.holds != NULL_MAP)) {
  219.     errh.ErrorExit("Map& Map::operator=(Map&)",
  220.                    "Illegal assignment attempted", *this, m);
  221.   }
  222.   range = m.range;
  223.   domain = m.domain;
  224.   t = m.t;
  225.   invt = m.invt;
  226.   invertible = m.invertible;
  227.   holds = m.holds;
  228.   hasAL = m.hasAL;
  229.   isDefault = m.isDefault;
  230.   domtype = m.domtype;
  231.   rettype = m.rettype;
  232.   return (*this);
  233. }
  234.  
  235. // ***********************************************************************
  236. //
  237. // Output for debugging:
  238. //
  239.  
  240. void Map::debug_out(ostream &c, int indent) 
  241. {
  242.   static char* name = "Map Object\n";
  243.   this->data_out(c, indent, name);
  244.   return;
  245. }
  246.  
  247. // ***********************************************************************
  248. //
  249. // If the MultiMap has an atomic VSpace or ASpace for a domain, it
  250. // can be converted to a map.  Alternately, if it is a fully evaluated
  251. // map that evaluates to a vector, it can be converted to a map from
  252. // the dual space to the Reals.
  253. //
  254.  
  255. Map::Map(MultiMap &m)
  256. {
  257.   static char* sig = "Map::Map(MultiMap&)";
  258.  
  259.   type = ANY_MAP;
  260.  
  261.   if (m.FullyEvaluated()) {
  262.     *this = Map(GeOb(m));
  263.   } else {
  264.  
  265. //  Check that the domain is an atomic VSpace or ASpace:
  266.  
  267.     if (m.DomainSpace().CPSpaceSize() != 1) {
  268.       errh.ErrorExit(sig, "Domain of multimap must be an atomic space", m);
  269.     }
  270.  
  271.     holds = (m.Holds() == MULTI_LINEAR) ? LIN_MAP : AFF_MAP;
  272.  
  273.     range = m.RangeSpace().FullSet();
  274.     domain = m.DomainSpace().FullSet();
  275.     domtype = m.DomainType();
  276.     rettype = m.RetType();
  277.     isDefault = FALSE;
  278.     hasAL = (domtype == AFF_POINT);
  279.  
  280.     int ddim = m.DomainSpace().MatrixSize();
  281.     int rdim = m.RangeSpace().MatrixSize();
  282.  
  283.     t = Matrix(ddim, rdim);
  284.     for (int i = 0; i < ddim; i++) {
  285.       t[i] = (m.GetStdImage(i))[0];
  286.     }
  287.  
  288.     if ((ddim == rdim) && (fabs(Det(t)) > EPSILON)) {
  289.       invertible = TRUE;
  290.       invt = Inverse(t);
  291.     } else {
  292.       invertible = FALSE;
  293.     }
  294.   }
  295. }
  296.  
  297. // ***********************************************************************
  298. //
  299. // If the GeOb is a vector, it can be converted to a map from the
  300. // dual space to the Reals.
  301. //
  302.  
  303. Map::Map(GeOb& g)
  304. {
  305.   static char* sig = "Map::Map(GeOb&)";
  306.   GeOb temp;
  307.  
  308.   type = ANY_MAP;
  309.  
  310.   if ((g.Holds() == VECTOR) || (g.Holds() == AFF_VECTOR)) {
  311.     temp = g;
  312.   } else if (g.CanMapTo(VECTOR)) {
  313.     temp = g.MapTo(VECTOR);
  314.   } else {
  315.     errh.ErrorExit(sig, "GeOb cannot be mapped to a vector", g);
  316.   }
  317.  
  318.   range = Reals.FullSet();
  319.   domain = temp.SpaceOf().Dual().FullSet();
  320.   t = Transpose(temp.MatrixRep());
  321.  
  322.   if (domain.EmbeddingSpace().Dim() == 1) {
  323.     invt = Inverse(t);
  324.     invertible = TRUE;
  325.   } else {
  326.     invertible = FALSE;
  327.   }
  328.  
  329.   holds = LIN_MAP;
  330.   hasAL = FALSE;
  331.   isDefault = FALSE;
  332.   domtype = domain.EmbeddingSpace().NativeType();
  333.   rettype = VECTOR;
  334.  
  335. // ***********************************************************************
  336. //
  337. // Map application.
  338. //
  339. // It probably makes sense to also provide a special map application operator
  340. // (to the implementing classes ONLY) that assumes its argument is
  341. // the correct type and fills in a result at a location specified
  342. // by an argument pointer.  This would help standard mappings be more
  343. // efficient.
  344. //
  345.  
  346. GeOb Map::operator()(GeOb& v)
  347. {
  348.   static char* sig = "GeOb Map::operator()(GeOb&)";
  349.  
  350.   if (v.CanMapTo(domtype)) {
  351.     GeOb temp = v.MapTo(domtype);
  352.     if (temp.SpaceOf() != domain.EmbeddingSpace()) {
  353.       errh.ErrorExit(sig, "Object cannot be mapped to domain space", *this, v);
  354.     } 
  355.     if (!domain.IsIn(temp)) {
  356.       errh.ErrorExit(sig, "Mapped object not in specified domain subset",
  357.                   *this, temp);
  358.     }
  359.     if (domtype == PROJ_POINT && holds == AFF_MAP) {
  360.       temp = domain.Normalize(temp);
  361.     }
  362.     Matrix retmat = temp.MatrixRep();
  363.     if (!isDefault) {
  364.       retmat = retmat * t;
  365.     }
  366.     GeOb retval(rettype, range.EmbeddingSpace(), retmat);
  367.     return (retval);
  368.   } else if (hasAL && v.CanMapTo(AFF_VECTOR)) {
  369.     return (this->ApplyAL(v));
  370.   } else {
  371.     errh.ErrorExit(sig, "Object cannot be mapped into domain space",
  372.                *this, v);
  373.   } 
  374. }
  375.  
  376. // ***********************************************************************
  377. //
  378. // Since inverses are computed when the map is created, this is cheap. 
  379. //
  380.  
  381. Map Map::Inv(void)
  382. {
  383.   static char* sig = "Map Map::Inv(void)";
  384.  
  385.   if (!invertible) {
  386.     errh.ErrorExit(sig, "Map is not invertible", *this);
  387.   }
  388.   Boolean hal = ((holds == AFF_MAP) &&
  389.          (domtype != PROJ_POINT) &&
  390.          (rettype == AFF_POINT));
  391.   Map retval(holds, invertible, domain, range, invt, t,
  392.          isDefault, hal, rettype, domtype);
  393.   return (retval);
  394. }
  395.  
  396. // ***********************************************************************
  397. //
  398. // Composition of two maps of the same type:
  399. //
  400.  
  401. Map Map::Compose(Map &m)
  402. {
  403.   static char* sig = "Map Map::Compose(Map&)";
  404.   Scalar factor = 1.0;
  405.  
  406.   if (holds == m.Holds()) {
  407.     if (!domain.IsSubset(m.Range())) {
  408.       errh.ErrorExit(sig,
  409.              "Range of first map not a subset of domain of second map",
  410.              *this, m);
  411.     }
  412.  
  413. // Affine maps into/outof projective spaces need a factor to account
  414. // for the need to normalize the offsets of the subsets:
  415.  
  416.     if ((domain.EmbeddingSpace().Holds() == PROJ_SPACE) &&
  417.        (domain.Holds() == AFFINE_SUBSET)) {
  418.       factor = domain.NormVal(m.Range());
  419.     } 
  420.     
  421.     Boolean cinv = invertible && m.Invertible() && m.Range().IsSubset(domain);
  422.     Matrix ct = factor * m.t * t;
  423.     Matrix cinvt;
  424.     if (cinv) {
  425.       cinvt = (1.0 / factor) * invt * m.invt;
  426.     }
  427.     GeObType cdt = m.DomainType();
  428.     GeObType crt = rettype;
  429.     Boolean chal = ((holds == AFF_MAP) &&
  430.             (cdt == AFF_POINT) && (crt != PROJ_POINT)); 
  431.     Boolean cisdf = isDefault && m.isDefault;
  432.     Map retval(holds, cinv, range, m.Domain(), ct, cinvt, 
  433.            cisdf, chal, cdt, crt);
  434.     return (retval);
  435.   } else {
  436.     errh.ErrorExit(sig, "Cannot compose different map types", *this, m);
  437.   }
  438. }
  439.  
  440. // ***********************************************************************
  441. //
  442. // A common operation in graphics programming is to compose affine
  443. // and projective maps to get a projective map.  This operation
  444. // does this composition by automatically casting any affine maps
  445. // to projective maps:
  446. //
  447.  
  448. ProjectiveMap Map::ComposeProj(Map &m)
  449. {
  450.   ProjectiveMap first;
  451.   ProjectiveMap second;
  452.   
  453.   if (holds == PROJ_MAP) {
  454.     first = *this;
  455.   } else {
  456.     first = this->InducedProjective();
  457.   }
  458.  
  459.   if (m.Holds() == PROJ_MAP) {
  460.     second = m;
  461.   } else {
  462.     second = m.InducedProjective();
  463.   }
  464.  
  465.   return (first.Compose(second));
  466. }
  467.  
  468. // ***********************************************************************
  469. //
  470. // Given an affine map between two full affine spaces, we frequently desire
  471. // the corresponding projective map between the neighboring projective
  472. // completion spaces: 
  473. //
  474.  
  475. ProjectiveMap Map::InducedProjective(void)
  476. {
  477.   static char* sig = "ProjectiveMap Map::InducedProjective(void)";
  478.  
  479. // For the current implementation, restrict this operation to affine
  480. // maps between full affine subsets of affine spaces.
  481.  
  482.   if (holds != AFF_MAP) {
  483.     errh.ErrorExit(sig,
  484.     "Can only take induced projective map for an affine map", *this);
  485.   }
  486.  
  487.   if ((range.EmbeddingSpace().Holds() != AFF_SPACE ) ||
  488.       (domain.EmbeddingSpace().Holds() != AFF_SPACE ) ||
  489.       (!range.IsFullSpace()) || (!domain.IsFullSpace())) {
  490.     errh.ErrorExit(sig,
  491.            "Only implemented for maps between full affine spaces",
  492.            *this);
  493.   }
  494.  
  495. // Require that the map be invertible; otherwise, we would need to 
  496. // build a special domain subset for the projective map:
  497.  
  498.   if (!invertible) {
  499.     errh.ErrorExit(sig, "Map must be invertible", *this);
  500.   }
  501.  
  502.   SubSet td = domain.EmbeddingSpace().GetSpace(PROJECT_COMP).FullSet();
  503.   SubSet tr = range.EmbeddingSpace().GetSpace(PROJECT_COMP).FullSet();
  504.   GeObType trt = PROJ_POINT;
  505.   GeObType tdt = PROJ_POINT;
  506.  
  507.   Matrix newt = td.EmbeddingSpace().AffineMapTo(AFFINE).t * t *
  508.                 range.EmbeddingSpace().AffineMapTo(PROJECT_COMP).t;
  509.  
  510.   Matrix newinvt = tr.EmbeddingSpace().AffineMapTo(AFFINE).t * invt *
  511.                    domain.EmbeddingSpace().AffineMapTo(PROJECT_COMP).t;
  512.  
  513.   Map retval(PROJ_MAP, invertible, tr, td, newt, newinvt,
  514.          FALSE, FALSE, tdt, trt);
  515.   return retval;  
  516. }
  517.  
  518. // ***********************************************************************
  519. //
  520. // Given an affine map between two full affine spaces, this gives the
  521. // corresponding linear map between the neighboring linearization spaces: 
  522. //
  523.  
  524. LinearMap Map::InducedLinear(void)
  525. {
  526.   static char* sig = "LinearMap Map::InducedLinear(void)";
  527.  
  528. // For the current implementation, restrict this operation to affine
  529. // maps between full affine subsets of affine spaces.
  530.  
  531.   if (holds != AFF_MAP) {
  532.     errh.ErrorExit(sig,
  533.     "Can only take induced linear map for an affine map", *this);
  534.   }
  535.  
  536.   if ((range.EmbeddingSpace().Holds() != AFF_SPACE ) ||
  537.       (domain.EmbeddingSpace().Holds() != AFF_SPACE ) ||
  538.       (!range.IsFullSpace()) || (!domain.IsFullSpace())) {
  539.     errh.ErrorExit(sig,
  540.            "Only implemented for maps between full affine spaces",
  541.            *this);
  542.   }
  543.  
  544.   SubSet td = domain.EmbeddingSpace().GetSpace(LINEARIZATION).FullSet();
  545.   SubSet tr = range.EmbeddingSpace().GetSpace(LINEARIZATION).FullSet();
  546.   GeObType trt = VECTOR;
  547.   GeObType tdt = VECTOR;
  548.  
  549.   Matrix newt = td.EmbeddingSpace().AffineMapTo(AFFINE).t * t *
  550.                 range.EmbeddingSpace().AffineMapTo(LINEARIZATION).t;
  551.  
  552.   Matrix newinvt;
  553.   if (invertible) {
  554.     newinvt = tr.EmbeddingSpace().AffineMapTo(AFFINE).t * invt *
  555.               domain.EmbeddingSpace().AffineMapTo(LINEARIZATION).t;
  556.   }
  557.  
  558.   Map retval(LIN_MAP, invertible, tr, td, newt, newinvt, 
  559.          FALSE, FALSE, tdt, trt);
  560.   return retval;  
  561. }
  562.  
  563. // ***********************************************************************
  564. //
  565. // The transpose of a map V -> U is a map U' -> V'.  Currently only
  566. // implemented for maps between full spaces.
  567. //
  568.  
  569. LinearMap Map::Trans(void)
  570. {
  571.   static char* sig = "LinearMap Map::Trans(void)";
  572.  
  573. // Make sure this map is linear:
  574.  
  575.   if (holds != LIN_MAP) {
  576.     errh.ErrorExit(sig, "Can only take transpose of a linear map", *this);
  577.   }
  578.  
  579.   if (!range.IsFullSpace() || !domain.IsFullSpace()) {
  580.     errh.ErrorExit(sig,
  581.            "Only implemented for maps between full spaces", *this);
  582.   }
  583.  
  584. // Need to get the dual subspaces for the range and domain,
  585. // and swap them:
  586.  
  587.   SubSet td = range.EmbeddingSpace().Dual().FullSet();
  588.   SubSet tr = domain.EmbeddingSpace().Dual().FullSet();
  589.   GeObType trt = tr.EmbeddingSpace().NativeType();
  590.   GeObType tdt = td.EmbeddingSpace().NativeType();
  591.  
  592.   Map retval(LIN_MAP, invertible, tr, td, Transpose(t),
  593.          Transpose(invt), FALSE, FALSE, tdt, trt);
  594.   return retval;  
  595. }
  596.  
  597. // ***********************************************************************
  598. //
  599. // If this is map A -> X, with A a subset of an affine space and X a
  600. // subset of a linear or affine space, this is the map induced on the
  601. // tangent space A.v: 
  602. //
  603.  
  604. LinearMap Map::AssocLinear(void)
  605. {
  606.   static char* sig = "LinearMap Map::AssocLinear(void)";
  607.  
  608. // First need to make sure that the map has an associated linear map:
  609.  
  610.   if (!hasAL) {
  611.     errh.ErrorExit(sig, "Map does not have an associated linear map", *this);
  612.   }
  613.  
  614. // Start to build matrix:
  615.  
  616.   Matrix hold = domain.EmbeddingSpace().HoistTangent();
  617.   Matrix holdr = range.EmbeddingSpace().HoistTangent();
  618.   Matrix alt = hold * t;
  619.   Matrix alinvt;      
  620.   if (invertible) alinvt = invt * Transpose(hold);
  621.  
  622. // The range depends on the character of the affine map.  If it is
  623. // to an affine subset of an affine space, the range is the
  624. // corresponding subspace of the tangent space.  If it is to an
  625. // affine subset of a vector space, the range is a vector
  626. // subspace in the vector space.  If it is to a vector subset,
  627. // this range is the same vector subset.
  628.  
  629.   SubSet alr;
  630.   GeObType alrt;
  631.  
  632.   if (range.EmbeddingSpace().Holds() == AFF_SPACE) {
  633.     alr = range.TangentSub();
  634.     alrt = AFF_VECTOR;
  635.     alt = alt * Transpose(holdr);
  636.     if (invertible) alinvt = holdr * alinvt;
  637.   } else if (range.Holds() == AFFINE_SUBSET) {
  638.     alr = range.TangentSub();
  639.     alrt = VECTOR;
  640.   } else {
  641.     alr = range;
  642.     alrt = VECTOR;
  643.   }
  644.  
  645.   Map retval(LIN_MAP, invertible, alr, domain.TangentSub(), alt,
  646.          alinvt, FALSE, FALSE, AFF_VECTOR, alrt);
  647.   return retval;  
  648. }
  649.  
  650. // ***********************************************************************
  651. //
  652. // If this map is an affine functional (i.e. an affine map into the reals),
  653. // this returns the vector in the dual of the tangent space corresponding
  654. // to the associated linear map.
  655. //
  656.  
  657. Vector Map::AssocDualVector(void)
  658. {
  659.   static char* sig = "Vector Map::AssocDualVector(void)";
  660.   Space res = range.EmbeddingSpace();
  661.  
  662.   if ((holds != AFF_MAP) || (res != Reals)) {
  663.     errh.ErrorExit(sig, "Not an affine map into the Reals", *this);
  664.   }
  665.  
  666.   Vector retval = Vector(this->AssocLinear());
  667.   return (retval);
  668. }
  669.  
  670.  
  671.  
  672. // ***********************************************************************
  673. // ***********************************************************************
  674. //
  675. // LinearMap Class
  676. //
  677. // ***********************************************************************
  678. // ***********************************************************************
  679. //
  680. // Public member functions
  681. //
  682. // ***********************************************************************
  683. //
  684. // A map can only be cast down to a Linear Map if it is one (no
  685. // conversions).
  686. //
  687.  
  688. LinearMap::LinearMap(Map &m) : (m)
  689. {
  690.   type = LIN_MAP;
  691.   if ((holds != LIN_MAP) && (holds != NULL_MAP)) {
  692.       errh.ErrorExit("LinearMap::LinearMap(Map &)",
  693.                      "Attempted to cast a non-linear map to a linear map", m);
  694.   }
  695. }
  696.  
  697. // ***********************************************************************
  698. //
  699. // Need to do memberwise assignment, since Matrix class members need to
  700. // do memberwise assignment:
  701. //
  702.  
  703. LinearMap& LinearMap::operator=(LinearMap& m)
  704. {
  705.   range = m.range;
  706.   domain = m.domain;
  707.   t = m.t;
  708.   invt = m.invt;
  709.   invertible = m.invertible;
  710.   holds = m.holds;
  711.   hasAL = m.hasAL;
  712.   isDefault = m.isDefault;
  713.   domtype = m.domtype;
  714.   rettype = m.rettype;
  715.   return (*this);
  716. }
  717.  
  718. // ***********************************************************************
  719. //
  720. // Output for debugging:
  721. //
  722.  
  723. void LinearMap::debug_out(ostream &c, int indent) 
  724. {
  725.   static char* name = "LinearMap Object\n";
  726.   this->data_out(c, indent, name);
  727.   return;
  728. }
  729.  
  730. // ***********************************************************************
  731. //
  732. // Simplest kind of map creation.  Since we are going between bases,
  733. // the map is invertible, and no subsets are involved:
  734. //
  735.  
  736. LinearMap::LinearMap(VBasis &b1, VBasis &b2)
  737. {
  738.   static char* sig = "LinearMap::LinearMap(VBasis&, VBasis&)";
  739.  
  740.   type = LIN_MAP;
  741.   holds = LIN_MAP;
  742.   domain = b1.SpaceOf().FullSet();
  743.   range = b2.SpaceOf().FullSet();
  744.   hasAL = FALSE;
  745.   isDefault = FALSE;
  746.   domtype = b1.SpaceOf().NativeType();
  747.   rettype = b2.SpaceOf().NativeType();
  748.  
  749.   if (range.Dim() != domain.Dim()) {
  750.     errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
  751.   }
  752.  
  753.   t = b1.Fromstdb() * b2.Tostdb();
  754.   if (fabs(Det(t)) > EPSILON) {
  755.     invt = Inverse(t);
  756.     invertible = TRUE;
  757.   } else {
  758.     errh.ErrorExit(sig, "Unexpected error", b1, b2);
  759.   }
  760. }
  761.  
  762. // ***********************************************************************
  763. //
  764. // More general map creation.  The domain of the map is a whole space,
  765. // but the range can be a subset.  Each item in the GeObList represents
  766. // the image of the corresponding object in the basis.
  767.  
  768. LinearMap::LinearMap(VBasis& b, VSubSet& s, GeObList& v)
  769. {
  770.   static char* sig = "LinearMap::LinearMap(VBasis&, VSubSet&, GeObList&)";
  771.   Space rspace = s.EmbeddingSpace();
  772.  
  773.   type = LIN_MAP;
  774.   holds = LIN_MAP;
  775.   domain = b.SpaceOf().FullSet();
  776.   range = s;
  777.   hasAL = FALSE;
  778.   isDefault = FALSE;
  779.   domtype = b.SpaceOf().NativeType();
  780.   rettype = rspace.NativeType();
  781.  
  782. // Make sure that enough image objects have been specified:
  783.  
  784.   if (v.Length() != domain.Dim()) {
  785.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
  786.   }
  787.  
  788. // Map the objects into the range subset and use them to start building
  789. // the transform matrix:
  790.  
  791.   GeObType target = rspace.NativeType();
  792.   Matrix temp(v.Length(), rspace.Dim());
  793.  
  794.   if (!(this->ConvertList(v, target, range, &temp))) {
  795.     errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
  796.   } 
  797.  
  798. // Build the transform matrix, and then start to build the inverse by
  799. // converting the range objects to the subspace basis representation:
  800.  
  801.   t = b.Fromstdb() * temp;
  802.   temp = temp * range.FromFull();
  803.  
  804. // Now figure out if the map is invertible.  Two requirements must
  805. // be met.  The dimension of the range and domain subsets must match,
  806. // and the specified image objects in the range must be independent.
  807.  
  808.   if (range.Dim() != domain.Dim()) {
  809.     invertible = FALSE;
  810.   } else {
  811.     invertible = (fabs(Det(temp)) > EPSILON);
  812.   }
  813.  
  814.   if (invertible) {
  815.     invt = range.FromFull() * Inverse(temp) * b.Tostdb();
  816.   }
  817. }
  818.  
  819. // ***********************************************************************
  820. //
  821. // The reverse of the above constructor.
  822. //
  823.  
  824. LinearMap::LinearMap(VSubSet &s, GeObList &v, VBasis &b)
  825. {
  826.   static char* sig = "LinearMap::LinearMap(VSubSet&, GeObList&, VBasis&)";
  827.   Space dspace = s.EmbeddingSpace();
  828.  
  829.   type = LIN_MAP;
  830.   holds = LIN_MAP;
  831.   domain = s;
  832.   range = b.SpaceOf().FullSet();
  833.   hasAL = FALSE;
  834.   isDefault = FALSE;
  835.   domtype = dspace.NativeType();
  836.   rettype = b.SpaceOf().NativeType();
  837.  
  838. // Make sure that enough preimage objects have been specified:
  839.  
  840.   if (v.Length() != range.Dim()) {
  841.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
  842.   }
  843.   if (range.Dim() != domain.Dim()) {
  844.     errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
  845.   }
  846.  
  847. // Map the objects into the domain subset and use them to start building
  848. // the transform matrix:
  849.  
  850.   GeObType target = dspace.NativeType();
  851.   Matrix temp1(v.Length(), dspace.Dim());
  852.  
  853.   if (!(this->ConvertList(v, target, domain, &temp1))) {
  854.     errh.ErrorExit(sig,
  855.            "Object cannot be mapped into domain subset", v, domain);
  856.   } 
  857.  
  858. // We now need to confirm that the preimage objects we have been given
  859. // span the domain subset.  If they do, build the transform matrix:
  860.  
  861.   Matrix temp2 = temp1 * domain.FromFull();
  862.   if (fabs(Det(temp2)) <= EPSILON) {
  863.     errh.ErrorExit(sig, "Objects in domain are not independent", v, s);
  864.   }
  865.   t = domain.FromFull() * Inverse(temp2) * b.Tostdb();
  866.  
  867. // Maps built this way must be invertible, so build the inverse:
  868.  
  869.   invertible = TRUE;
  870.   invt = b.Fromstdb() * temp1;
  871. }
  872.  
  873. // ***********************************************************************
  874. //
  875. // Here is the most general linear map constructor.
  876. //
  877.  
  878. LinearMap::LinearMap(VSubSet &s1, GeObList &v1, VSubSet &s2, GeObList &v2)
  879. {
  880.   static char* sig =
  881.     "LinearMap::LinearMap(VSubSet&, GeObList&, VSubSet&, GeObList&)";
  882.   Space dspace = s1.EmbeddingSpace();
  883.   Space rspace = s2.EmbeddingSpace();
  884.  
  885.   type = LIN_MAP;
  886.   holds = LIN_MAP;
  887.   domain = s1;
  888.   range = s2;
  889.   hasAL = FALSE;
  890.   isDefault = FALSE;
  891.   domtype = dspace.NativeType();
  892.   rettype = rspace.NativeType();
  893.  
  894. // Make sure that enough preimage and image objects have been specified:
  895.  
  896.   if (v1.Length() != domain.Dim()) {
  897.     errh.ErrorExit(sig, "Incorrect number of objects specified", s1, v1);
  898.   }
  899.   if (v2.Length() != v1.Length()) {
  900.     errh.ErrorExit(sig, "Incorrect number of objects specified", s1, s2, v2);
  901.   }
  902.  
  903. // Map the objects into the domain and range subsets and use them to start
  904. // building the transform matrix:
  905.  
  906.   GeObType target = dspace.NativeType();
  907.   Matrix tempd(v1.Length(), dspace.Dim());
  908.  
  909.   if (!(this->ConvertList(v1, target, domain, &tempd))) {
  910.     errh.ErrorExit(sig,
  911.            "Object cannot be mapped into domain subset", v1, domain);
  912.   } 
  913.  
  914.   target = rspace.NativeType();
  915.   Matrix tempr(v2.Length(), rspace.Dim());
  916.  
  917.   if (!(this->ConvertList(v2, target, range, &tempr))) {
  918.     errh.ErrorExit(sig,
  919.            "Object cannot be mapped into range subset", v2, range);
  920.   } 
  921.  
  922. // We now need to confirm that the preimage objects we have been given
  923. // span the domain subset.  If they do, build the transform matrix, and
  924. // then start to build the inverse by converting the range objects to
  925. // their subspace basis representation:
  926.  
  927.   Matrix tempd2 = tempd * domain.FromFull();
  928.   if (fabs(Det(tempd2)) <= EPSILON) {
  929.     errh.ErrorExit(sig, "Objects in domain are not independent", v1, s1);
  930.   }
  931.   t = domain.FromFull() * Inverse(tempd2) * tempr;
  932.   tempr = tempr * range.FromFull();
  933.  
  934. // Now figure out if the map is invertible.  Two requirements must
  935. // be met.  The dimension of the range and domain subsets must match,
  936. // and the specified image objects in the range must be independent.
  937.  
  938.   if (range.Dim() != domain.Dim()) {
  939.     invertible = FALSE;
  940.   } else {
  941.     invertible = (fabs(Det(tempr)) > EPSILON);
  942.   }
  943.  
  944.   if (invertible) {
  945.     invt = range.FromFull() * Inverse(tempr) * tempd;
  946.   }
  947. }
  948.  
  949. // ***********************************************************************
  950. // ***********************************************************************
  951. //
  952. // AffineMap Class
  953. //
  954. // ***********************************************************************
  955. // ***********************************************************************
  956. //
  957. // Private/protected member functions
  958. //
  959. // ***********************************************************************
  960. //
  961. // Builds the default standard affine maps between spaces in a space set.
  962. //
  963.  
  964. AffineMap::AffineMap(Space &s1, Space &s2)
  965. {
  966.   static char* sig = "AffineMap::AffineMap(Space&, Space&)";
  967.  
  968. // Standard affine maps go between standard affine subsets.  Determine
  969. // if these spaces have defined subsets; create them if they do not,
  970. // get them if they do.
  971.  
  972.   domain = s1.StdAffineSubset();
  973.   range = s2.StdAffineSubset(); 
  974.  
  975.   if (domain.Holds() == NULL_SUBSET) {
  976.     domain = ASubSet(s1);
  977.   }
  978.  
  979.   if (range.Holds() == NULL_SUBSET) {
  980.     range = ASubSet(s2);
  981.   }
  982.  
  983.   type = AFF_MAP;
  984.   holds = AFF_MAP;
  985.   invertible = TRUE;
  986.   isDefault = TRUE;
  987.   domtype = s1.NativeType();
  988.   rettype = s2.NativeType();
  989.  
  990.   SRel s1t = s1.ThisSpaceIs();
  991.   SRel s2t = s2.ThisSpaceIs();
  992.   Space check = s1.GetSpace(s2t);
  993.  
  994.   if (check != s2) {
  995.     errh.ErrorExit(sig, "Spaces are not linked", s1, s2);
  996.   }
  997.  
  998.   hasAL = (s1t == AFFINE) && (s2t == LINEARIZATION);
  999.   t = IdentityMatrix(s1.MatrixSize());
  1000.   invt = t;
  1001. }
  1002.  
  1003. // ***********************************************************************
  1004. //
  1005. // Builds a consistent affine map for linking an affine space to
  1006. // a linearization space.  USER IS RESPONSIBLE FOR COPYING STD.
  1007. // AFFINE SUBSET GENERATED IN THIS ROUTINE TO THE EMBEDDING SPACE.
  1008.  
  1009.  
  1010. AffineMap::AffineMap(AffineMap& apm, ProjectiveMap& lpm)
  1011. {
  1012.   Space P = apm.Range().EmbeddingSpace();
  1013.   Space A = apm.Domain().EmbeddingSpace();
  1014.  
  1015. // Linearization space needs a consistent standard affine subset.
  1016.  
  1017.   range = A.StdAffineSubset();
  1018.   domain = ASubSet(P.StdAffineSubset(), lpm.Inv());
  1019.   type = AFF_MAP;
  1020.   holds = AFF_MAP;
  1021.   invertible = TRUE;
  1022.   hasAL = FALSE;
  1023.   isDefault = FALSE;
  1024.   domtype = VECTOR;
  1025.   rettype = AFF_POINT;
  1026.  
  1027.   t = lpm.t * apm.invt;
  1028.   invt = Inverse(t);
  1029. }
  1030.  
  1031. // ***********************************************************************
  1032. //
  1033. // Builds a consistent affine map for linking an affine space to
  1034. // a projective space:  
  1035. //
  1036.  
  1037. AffineMap::AffineMap(ProjectiveMap& lpm, AffineMap& lam)
  1038. {
  1039.   Space L = lpm.Domain().EmbeddingSpace();
  1040.   Space A = lam.Range().EmbeddingSpace();
  1041.  
  1042. // Projective space does not yet have a standard affine subset.  It
  1043. // must be consistent with the linearization space standard affine
  1044. // subset.  USER IS RESPONSIBLE FOR COPYING STD.
  1045. // AFFINE SUBSET GENERATED IN THIS ROUTINE TO THE EMBEDDING SPACE.
  1046.  
  1047.   domain = A.StdAffineSubset();
  1048.   range = ASubSet(L.StdAffineSubset(), lpm);
  1049.   type = AFF_MAP;
  1050.   holds = AFF_MAP;
  1051.   invertible = TRUE;
  1052.   hasAL = FALSE;
  1053.   isDefault = FALSE;
  1054.   domtype = AFF_POINT;
  1055.   rettype = PROJ_POINT;
  1056.  
  1057.   t = lam.invt * lpm.t;
  1058.   invt = Inverse(t);
  1059. }
  1060.  
  1061. // ***********************************************************************
  1062. //
  1063. // Public member functions
  1064. //
  1065. // ***********************************************************************
  1066. //
  1067. // A map can only be cast down to an affine map if it is one (no
  1068. // conversions). 
  1069. //
  1070.  
  1071. AffineMap::AffineMap(Map &m) : (m)
  1072. {
  1073.   type = AFF_MAP;
  1074.   if ((holds != AFF_MAP) && (holds != NULL_MAP)) {
  1075.       errh.ErrorExit("AffineMap::AffineMap(Map&)",
  1076.          "Attempted to cast a non-affine map to an affine map", m);
  1077.   }
  1078. }
  1079.  
  1080. // ***********************************************************************
  1081. //
  1082. // Need to do memberwise assignment, since Matrix class members need to
  1083. // do memberwise assignment.
  1084. //
  1085.  
  1086. AffineMap& AffineMap::operator=(AffineMap& m)
  1087. {
  1088.   range = m.range;
  1089.   domain = m.domain;
  1090.   t = m.t;
  1091.   invt = m.invt;
  1092.   invertible = m.invertible;
  1093.   holds = m.holds;
  1094.   hasAL = m.hasAL;
  1095.   isDefault = m.isDefault;
  1096.   domtype = m.domtype;
  1097.   rettype = m.rettype;
  1098.   return (*this);
  1099. }
  1100.  
  1101. // ***********************************************************************
  1102. //
  1103. // Output for debugging:
  1104. //
  1105.  
  1106. void AffineMap::debug_out(ostream &c, int indent) 
  1107. {
  1108.   static char* name = "AffineMap Object\n";
  1109.   this->data_out(c, indent, name);
  1110.   return;
  1111. }
  1112.  
  1113. // ***********************************************************************
  1114. //
  1115. // Simplest kind of map creation.  Since we are going between bases,
  1116. // the map is invertible, and no subsets are involved.  Restrict this
  1117. // constructor to just handle maps between affine spaces (i.e. no
  1118. // maps from simplex to vbasis).
  1119. //
  1120.  
  1121. AffineMap::AffineMap(Basis &b1, Basis &b2)
  1122. {
  1123.   static char* sig = "AffineMap::AffineMap(Basis&, Basis&)";
  1124.  
  1125.   type = AFF_MAP;
  1126.   holds = AFF_MAP;
  1127.   domain = b1.SpaceOf().FullSet();
  1128.   range = b2.SpaceOf().FullSet();
  1129.   hasAL = TRUE;
  1130.   isDefault = FALSE;
  1131.   domtype = AFF_POINT;
  1132.   rettype = AFF_POINT;
  1133.  
  1134. // Check that the type of basis matches:
  1135.  
  1136.   BasisType b1t = b1.Holds();
  1137.   BasisType b2t = b2.Holds();
  1138.  
  1139.   if ((b1t != b2t) || !((b1t == SIMPLEX) || (b1t == FRAME))) {
  1140.     errh.ErrorExit(sig, "Specified bases are not of the correct type", b1, b2);
  1141.   }
  1142.  
  1143. // Check that the dimensionality matches:
  1144.  
  1145.   if (range.Dim() != domain.Dim()) {
  1146.     errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
  1147.   }
  1148.  
  1149.   t = b1.Fromstdb() * b2.Tostdb();
  1150.   if (fabs(Det(t)) > EPSILON) {
  1151.     invt = Inverse(t);
  1152.     invertible = TRUE;
  1153.   } else {
  1154.     errh.ErrorExit(sig, "Unexpected error", b1, b2);
  1155.   }
  1156. }
  1157.  
  1158. // ***********************************************************************
  1159. //
  1160. // Map from a full affine space into some affine or vector subset.
  1161. // We currently require that a simplex be used to define the domain
  1162. // preimage.
  1163. //
  1164.  
  1165. AffineMap::AffineMap(Simplex& b, SubSet& s, GeObList& v)
  1166. {
  1167.   static char* sig = "AffineMap::AffineMap(Simplex&, SubSet&, GeObList&)";
  1168.   Space rspace = s.EmbeddingSpace();
  1169.  
  1170.   type = AFF_MAP;
  1171.   holds = AFF_MAP;
  1172.   domain = b.SpaceOf().FullSet();
  1173.   range = s;
  1174.   domtype = AFF_POINT;
  1175.   rettype = rspace.NativeType();
  1176.   hasAL = (rettype != PROJ_POINT);
  1177.   isDefault = FALSE;
  1178.  
  1179. // Make sure the subset is an affine or linear subset and that enough
  1180. // image objects have been specified:
  1181.  
  1182.   if ((s.Holds() != LINEAR_SUBSET) && (s.Holds() != AFFINE_SUBSET)) {
  1183.     errh.ErrorExit(sig, "Specified subset is not linear or affine", s);
  1184.   }
  1185.   if (v.Length() != domain.Dim() + 1) {
  1186.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
  1187.   }
  1188.  
  1189. // Map the objects into the range subset and use them to start building
  1190. // the transform matrix:
  1191.  
  1192.   GeObType target = rspace.NativeType();
  1193.   Matrix temp(v.Length(), rspace.MatrixSize());
  1194.  
  1195.   if (!(this->ConvertList(v, target, range, &temp))) {
  1196.     errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
  1197.   } 
  1198.  
  1199. // Build the transform matrix, and then start to build the inverse by
  1200. // converting the range objects to the subspace basis representation:
  1201.  
  1202.   t = b.Fromstdb() * temp;
  1203.   temp = temp * range.FromFull();
  1204.  
  1205. // Now figure out if the map is invertible.  Three requirements must
  1206. // be met.  The dimension of the range and domain subsets must match,
  1207. // the range must be an affine subset, and the specified image objects
  1208. // in the range must be independent.
  1209.  
  1210.   if ((range.Dim() != domain.Dim()) || (range.Holds() != AFFINE_SUBSET)) {
  1211.     invertible = FALSE;
  1212.   } else {
  1213.     invertible = (fabs(Det(temp)) > EPSILON);
  1214.   }
  1215.  
  1216.   if (invertible) {
  1217.     invt = range.FromFull() * Inverse(temp) * b.Tostdb();
  1218.   }
  1219. }
  1220.  
  1221. // ***********************************************************************
  1222. //
  1223. // Map from an affine subset to a full affine space. 
  1224. //
  1225.  
  1226. AffineMap::AffineMap(ASubSet& s, GeObList& v, Simplex& b)
  1227. {
  1228.   static char* sig = "AffineMap::AffineMap(ASubSet&, GeObList&, Simplex&)";
  1229.   Space dspace = s.EmbeddingSpace();
  1230.  
  1231.   type = AFF_MAP;
  1232.   holds = AFF_MAP;
  1233.   domain = s;
  1234.   range = b.SpaceOf().FullSet();
  1235.   domtype = dspace.NativeType();
  1236.   rettype = AFF_POINT;
  1237.   hasAL = (domtype == AFF_POINT);
  1238.   isDefault = FALSE;
  1239.  
  1240. // Make sure the subset is an affine subset and that enough
  1241. // preimage objects have been specified:
  1242.  
  1243.   if (v.Length() != range.Dim() + 1) {
  1244.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
  1245.   }
  1246.   if (range.Dim() != domain.Dim()) {
  1247.     errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
  1248.   }
  1249.  
  1250. // Map the objects into the domain subset and use them to start building
  1251. // the transform matrix:
  1252.  
  1253.   GeObType target = dspace.NativeType();
  1254.   Matrix temp1(v.Length(), dspace.MatrixSize());
  1255.  
  1256.   if (!(this->ConvertList(v, target, domain, &temp1))) {
  1257.     errh.ErrorExit(sig,
  1258.            "Object cannot be mapped into domain subset", v, domain);
  1259.   } 
  1260.  
  1261. // We now need to confirm that the preimage objects we have been given
  1262. // span the domain subset.  If they do, build the transform matrix:
  1263.  
  1264.   Matrix temp2 = temp1 * domain.FromFull();
  1265.   if (fabs(Det(temp2)) <= EPSILON) {
  1266.     errh.ErrorExit(sig, "Objects in domain are not independent", v, s);
  1267.   }
  1268.   t = domain.FromFull() * Inverse(temp2) * b.Tostdb();
  1269.  
  1270. // Maps built this way must be invertible, so build the inverse:
  1271.  
  1272.   invertible = TRUE;
  1273.   invt = b.Fromstdb() * temp1;
  1274. }
  1275.  
  1276. // ***********************************************************************
  1277. //
  1278. // Most general constructor for affine maps. 
  1279. //
  1280.  
  1281. AffineMap::AffineMap(ASubSet &s1, GeObList &v1, SubSet &s2, GeObList &v2)
  1282. {
  1283.   static char* sig =
  1284.     "AffineMap::AffineMap(ASubSet&, GeObList&, SubSet&, GeObList&)";
  1285.   Space dspace = s1.EmbeddingSpace();
  1286.   Space rspace = s2.EmbeddingSpace();
  1287.  
  1288.   type = AFF_MAP;
  1289.   holds = AFF_MAP;
  1290.   domain = s1;
  1291.   range = s2;
  1292.  
  1293.   domtype = dspace.NativeType();
  1294.   rettype = rspace.NativeType();
  1295.   hasAL = ((domtype == AFF_POINT) && (rettype != PROJ_POINT));
  1296.   isDefault = FALSE;
  1297.  
  1298. // The range subspace can be either affine or linear.  Also make
  1299. // sure enough objects have been specified in each list:
  1300.  
  1301.   if ((s2.Holds() != LINEAR_SUBSET) && (s2.Holds() != AFFINE_SUBSET)) {
  1302.     errh.ErrorExit(sig, "Range subset is not linear or affine", s2);
  1303.   }
  1304.   if (v1.Length() != domain.Dim() + 1) {
  1305.     errh.ErrorExit(sig, "Incorrect number of objects specified", s1, v1);
  1306.   }
  1307.   if (v2.Length() != v1.Length()) {
  1308.     errh.ErrorExit(sig, "Incorrect number of objects specified", v1, s2, v2);
  1309.   }
  1310.  
  1311. // Map the objects into the domain and range subsets and use them to start
  1312. // building the transform matrix:
  1313.  
  1314.   GeObType target = dspace.NativeType();
  1315.   Matrix tempd(v1.Length(), dspace.MatrixSize());
  1316.  
  1317.   if (!(this->ConvertList(v1, target, domain, &tempd))) {
  1318.     errh.ErrorExit(sig,
  1319.            "Object cannot be mapped into domain subset", v1, domain);
  1320.   } 
  1321.  
  1322.   target = rspace.NativeType();
  1323.   Matrix tempr(v2.Length(), rspace.MatrixSize());
  1324.  
  1325.   if (!(this->ConvertList(v2, target, range, &tempr))) {
  1326.     errh.ErrorExit(sig,
  1327.            "Object cannot be mapped into range subset", v2, range);
  1328.   } 
  1329.  
  1330. // We now need to confirm that the preimage objects we have been given
  1331. // span the domain subset.  If they do, build the transform matrix, and
  1332. // then start to build the inverse by converting the range objects to
  1333. // their subspace basis representation:
  1334.  
  1335.   Matrix tempd2 = tempd * domain.FromFull();
  1336.   if (fabs(Det(tempd2)) <= EPSILON) {
  1337.     errh.ErrorExit(sig, "Objects in domain are not independent", v1, s1);
  1338.   }
  1339.   t = domain.FromFull() * Inverse(tempd2) * tempr;
  1340.   tempr = tempr * range.FromFull();
  1341.  
  1342. // Now figure out if the map is invertible.  Two requirements must
  1343. // be met.  The dimension of the range and domain subsets must match,
  1344. // and the specified image objects in the range must be independent.
  1345.  
  1346.   if (range.Dim() != domain.Dim()) {
  1347.     invertible = FALSE;
  1348.   } else {
  1349.     invertible = (fabs(Det(tempr)) > EPSILON);
  1350.   }
  1351.  
  1352.   if (invertible) {
  1353.     invt = range.FromFull() * Inverse(tempr) * tempd;
  1354.   }
  1355. }
  1356.  
  1357. // ***********************************************************************
  1358. // ***********************************************************************
  1359. //
  1360. // ProjectiveMap Class
  1361. //
  1362. // ***********************************************************************
  1363. // ***********************************************************************
  1364. //
  1365. // Private/protected member functions
  1366. //
  1367. // ***********************************************************************
  1368. //
  1369. // A core problem when constructing projective maps is scaling the
  1370. // rows of the transformation matrix so the "extra" point maps
  1371. // to its image.  This routine scales the rows of a matrix so the
  1372. // specified "unit point" matrix is the sum of the rows.  It does this
  1373. // by solving a system of equations:
  1374. //
  1375.  
  1376. Boolean ProjectiveMap::ScaleRows(Matrix* mat, Matrix& unit_pt)
  1377. {
  1378.   if (fabs(Det(*mat)) < EPSILON) {
  1379.     return (FALSE);
  1380.   }
  1381.   Matrix invmat = Inverse(*mat);
  1382.   
  1383. // Solve for the row coefficients.  If any coefficient = 0, the
  1384. // unit point was not in general position.  Otherwise, multiply
  1385. // the matrix rows by the coefficients, and report the success:
  1386.  
  1387.   Matrix coeff = unit_pt * invmat;
  1388.   for (int i = 0; i < coeff.Columns(); i++) {
  1389.     if (fabs(coeff[0][i]) < EPSILON) {
  1390.       return (FALSE);
  1391.     } else {
  1392.       (*mat)[i] = (coeff[0][i] * (*mat)[i])[0];
  1393.     }
  1394.   }
  1395.   return (TRUE);
  1396. }
  1397.  
  1398. // ***********************************************************************
  1399. //
  1400. // Similar to the general ConvertList routine, but sticks the last
  1401. // object into a separate Matrix:
  1402. //
  1403.  
  1404. Boolean ProjectiveMap::ConvertListUnit(GeObList& v, GeObType trg, SubSet& d,
  1405.                        Matrix* temp, Matrix* unit)
  1406. {
  1407.   Space destspace = d.EmbeddingSpace();
  1408.  
  1409.   for (int i = 0; i < v.Length(); i++) {
  1410.     GeOb hold = v[i].MapTo(trg);
  1411.     if (hold.SpaceOf() != destspace) {
  1412.       return (FALSE);
  1413.     } 
  1414.     if (!d.IsIn(hold)) {
  1415.       return (FALSE);
  1416.     }
  1417.     if (i == v.Length() - 1) {
  1418.       (*unit)[0] = hold.MatrixRep()[0];
  1419.     } else {
  1420.       (*temp)[i] = hold.MatrixRep()[0];
  1421.     }
  1422.   }
  1423.   return (TRUE);
  1424. }
  1425.  
  1426.  
  1427. // ***********************************************************************
  1428. //
  1429. // Builds the default standard projective maps between spaces in a space set.
  1430. // One space must be projective, the other a linearization space.
  1431.  
  1432. ProjectiveMap::ProjectiveMap(Space& s1, Space& s2)
  1433. {
  1434.   static char* sig = "ProjectiveMap::ProjectiveMap(Space&, Space&)";
  1435.  
  1436.   domain = s1.FullProjSet();
  1437.   range = s2.FullProjSet();
  1438.  
  1439.   type = PROJ_MAP;
  1440.   holds = PROJ_MAP;
  1441.   invertible = TRUE;
  1442.   hasAL = FALSE;
  1443.   isDefault = TRUE;
  1444.   domtype = domain.Accepts();
  1445.   rettype = range.Accepts();
  1446.  
  1447.   SRel s1t = s1.ThisSpaceIs();
  1448.   SRel s2t = s2.ThisSpaceIs();
  1449.   Space check = s1.GetSpace(s2t);
  1450.  
  1451.   if (check != s2) {
  1452.     errh.ErrorExit(sig, "Spaces are not linked", s1, s2);
  1453.   }
  1454.  
  1455.   t = IdentityMatrix(s1.MatrixSize());
  1456.   invt = t;
  1457. }
  1458.  
  1459. // ***********************************************************************
  1460. //
  1461. // Builds a consistent projective map for linking a projective space to
  1462. // a linearization space.
  1463. //
  1464.  
  1465. ProjectiveMap::ProjectiveMap(VSpace& L, AffineMap& lpm, PSpace& P)
  1466. {
  1467.   domain = L.FullProjSet();
  1468.   range = P.FullSet();
  1469.   type = PROJ_MAP;
  1470.   holds = PROJ_MAP;
  1471.   invertible = TRUE;
  1472.   hasAL = FALSE;
  1473.   isDefault = lpm.isDefault;
  1474.   domtype = VEC_EC;
  1475.   rettype = PROJ_POINT;
  1476.  
  1477.   t = lpm.t;
  1478.   invt = Inverse(t);
  1479. }
  1480.  
  1481. // ***********************************************************************
  1482. //
  1483. // Public member functions
  1484. //
  1485. // ***********************************************************************
  1486. //
  1487. // A map can only be cast down to a Projective Map if it is one (no
  1488. // conversions). 
  1489.  
  1490. ProjectiveMap::ProjectiveMap(Map &m) : (m)
  1491. {
  1492.   type = PROJ_MAP;
  1493.   if ((holds != PROJ_MAP) && (holds != NULL_MAP)) {
  1494.       errh.ErrorExit("ProjectiveMap::ProjectiveMap(Map&)",
  1495.          "Attempted to cast a non-projective map to a projective map", m);
  1496.   }
  1497. }
  1498.  
  1499. // ***********************************************************************
  1500. //
  1501. // Need to do memberwise assignment, since Matrix class members need to
  1502. // do memberwise assignment:
  1503. //
  1504.  
  1505. ProjectiveMap& ProjectiveMap::operator=(ProjectiveMap& m)
  1506. {
  1507.   range = m.range;
  1508.   domain = m.domain;
  1509.   t = m.t;
  1510.   invt = m.invt;
  1511.   invertible = m.invertible;
  1512.   holds = m.holds;
  1513.   hasAL = m.hasAL;
  1514.   isDefault = m.isDefault;
  1515.   domtype = m.domtype;
  1516.   rettype = m.rettype;
  1517.   return (*this);
  1518. }
  1519.  
  1520. // ***********************************************************************
  1521. //
  1522. // Debug output
  1523. //
  1524.  
  1525. void ProjectiveMap::debug_out(ostream &c, int indent) 
  1526. {
  1527.   static char* name = "ProjectiveMap Object\n";
  1528.   this->data_out(c, indent, name);
  1529.   return;
  1530. }
  1531.  
  1532. // ***********************************************************************
  1533. //
  1534. // Used for invertible maps between whole projective spaces:
  1535. //
  1536.  
  1537. ProjectiveMap::ProjectiveMap(HFrame &b1, HFrame &b2)
  1538. {
  1539.   static char* sig = "ProjectiveMap::ProjectiveMap(HFrame&, HFrame&)";
  1540.  
  1541.   type = PROJ_MAP;
  1542.   holds = PROJ_MAP;
  1543.   domain = b1.SpaceOf().FullSet();
  1544.   range = b2.SpaceOf().FullSet();
  1545.   hasAL = FALSE;
  1546.   isDefault = FALSE;
  1547.   domtype = PROJ_POINT;
  1548.   rettype = PROJ_POINT;
  1549.  
  1550. // Check that the type of basis matches:
  1551.  
  1552.   if ((b1.Holds() != HFRAME) || (b2.Holds() != HFRAME)) {
  1553.     errh.ErrorExit(sig, "Specified bases are not projective frames", b1, b2);
  1554.   }
  1555.  
  1556. // Check that the dimensionality matches:
  1557.  
  1558.   if (range.Dim() != domain.Dim()) {
  1559.     errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
  1560.   }
  1561.  
  1562.   t = b1.Fromstdb() * b2.Tostdb();
  1563.   if (fabs(Det(t)) > EPSILON) {
  1564.     invt = Inverse(t);
  1565.     invertible = TRUE;
  1566.   } else {
  1567.     errh.ErrorExit(sig, "Unexpected error", b1, b2);
  1568.   }
  1569. }
  1570.  
  1571. // ***********************************************************************
  1572. //
  1573. // Used for invertible maps from a whole projective space to
  1574. // a projective subset.  Since the only allowable method for
  1575. // creating non-invertible maps is to have a domain subset with
  1576. // removed points, we require the image objects to be independent.
  1577. // Note that the subset could be from a vector space.  The range
  1578. // subset cannot have removed points, since there would be no way
  1579. // of returning a unique point in the embedding space.
  1580. //
  1581.  
  1582. ProjectiveMap::ProjectiveMap(HFrame &b, PSubSet &s, GeObList &v)
  1583. {
  1584.   static char* sig =
  1585.       "ProjectiveMap::ProjectiveMap(HFrame&, PSubSet&, GeObList&)";
  1586.   Space rspace = s.EmbeddingSpace();
  1587.  
  1588.   type = PROJ_MAP;
  1589.   holds = PROJ_MAP;
  1590.   domain = b.SpaceOf().FullSet();
  1591.   range = s;
  1592.   hasAL = FALSE;
  1593.   isDefault = FALSE;
  1594.   domtype = PROJ_POINT;
  1595.   rettype = s.Accepts();
  1596.  
  1597. // Make that enough image objects have been specified.  Also, since 
  1598. // only invertible maps can be specified, check the dimensions:
  1599.  
  1600.   if (v.Length() != domain.Dim() + 2) {
  1601.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
  1602.   }
  1603.   if (range.Dim() != domain.Dim()) {
  1604.     errh.ErrorExit(sig, "Range and domain dimensions must be equal",
  1605.             range, domain);
  1606.   }
  1607.   if (range.HasRemovedPoints()) {
  1608.     errh.ErrorExit(sig, "Range subset cannot have removed points", range);
  1609.   }
  1610.  
  1611. // Map the objects into the range subset and use them to start building
  1612. // the transform matrix:
  1613.  
  1614.   int rdim = rspace.MatrixSize(); 
  1615.   Matrix temp(v.Length() - 1, rdim);
  1616.   Matrix unit(1, rdim);
  1617.  
  1618.   if (!(this->ConvertListUnit(v, rettype, range, &temp, &unit))) {
  1619.     errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
  1620.   } 
  1621.  
  1622. // Convert the range objects to the range subset basis representation, then
  1623. // scale the matrix rows:
  1624.  
  1625.   temp = temp * range.FromFull();
  1626.   unit = unit * range.FromFull();
  1627.   if (!(this->ScaleRows(&temp, unit))) {
  1628.     errh.ErrorExit(sig, "Range objects not in general position", v, s);
  1629.   }
  1630.  
  1631. // Build the transform matrix, then build the inverse:
  1632.  
  1633.   t = b.Fromstdb() * temp * range.ToFull();
  1634.   invt = range.FromFull() * Inverse(temp) * b.Tostdb();
  1635.   invertible = TRUE;
  1636. }
  1637.  
  1638. // ***********************************************************************
  1639. //
  1640. // Used for map from a projective subset to a projective space.  If
  1641. // subset has removed points, map will be non-invertible:
  1642. //
  1643.  
  1644. ProjectiveMap::ProjectiveMap(PSubSet &s, GeObList &v, HFrame &b)
  1645. {
  1646.   static char* sig =
  1647.      "ProjectiveMap::ProjectiveMap(PSubSet&, GeObList&, HFrame&)";
  1648.   Space dspace = s.EmbeddingSpace();
  1649.  
  1650.   type = PROJ_MAP;
  1651.   holds = PROJ_MAP;
  1652.   domain = s;
  1653.   range = b.SpaceOf().FullSet();
  1654.   hasAL = FALSE;
  1655.   isDefault = FALSE;
  1656.   domtype = s.Accepts();
  1657.   rettype = PROJ_POINT;
  1658.  
  1659. // Make sure that enough preimage objects have been specified.
  1660. // Check that the domain and range dimensions match.
  1661.  
  1662.   if (v.Length() != range.Dim() + 2) {
  1663.     errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
  1664.   }
  1665.   if (range.Dim() != domain.Dim()) {
  1666.     errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
  1667.   }
  1668.  
  1669. // Map the objects into the domain subset and use them to start building
  1670. // the transform matrix:
  1671.  
  1672.   int ddim = dspace.MatrixSize();
  1673.   Matrix temp(v.Length() - 1, ddim);
  1674.   Matrix unit(1, ddim);
  1675.  
  1676.   if (!(this->ConvertListUnit(v, domtype, domain, &temp, &unit))) {
  1677.     errh.ErrorExit(sig,
  1678.            "Object cannot be mapped into domain subset", v, domain);
  1679.   } 
  1680.  
  1681. // Convert the domain objects to the domain subset basis representation, then
  1682. // scale the matrix rows:
  1683.  
  1684.   temp = temp * domain.FromFull();
  1685.   unit = unit * domain.FromFull();
  1686.   if (!(this->ScaleRows(&temp, unit))) {
  1687.     errh.ErrorExit(sig, "Domain objects not in general position", v, s);
  1688.   } 
  1689.  
  1690. // Build the transform matrix:
  1691.  
  1692.   t = domain.FromFull() * Inverse(temp) * b.Tostdb();
  1693.  
  1694. // The invertibility of this transform depends on whether the domain
  1695. // subset has been defined to have removed points.  If it has, the
  1696. // map is not invertible.  Otherwise, calculate the inverse:
  1697.  
  1698.   invertible = !domain.HasRemovedPoints();
  1699.  
  1700.   if (invertible) {
  1701.     invt = b.Fromstdb() * temp * domain.ToFull();
  1702.   }
  1703. }
  1704.  
  1705. // ***********************************************************************
  1706. //
  1707. // Used for maps between subsets.  If domain subset has removed points,
  1708. // map will not be invertible:
  1709. //
  1710.  
  1711. ProjectiveMap::ProjectiveMap(PSubSet &s1, GeObList &v1,
  1712.                  PSubSet &s2, GeObList &v2)
  1713. {
  1714.   static char* sig =
  1715.       "ProjectiveMap::ProjectiveMap(PSubSet&, GeObList&, PSubSet&, GeObList&)";
  1716.   Space dspace = s1.EmbeddingSpace();
  1717.   Space rspace = s2.EmbeddingSpace();
  1718.  
  1719.   type = PROJ_MAP;
  1720.   holds = PROJ_MAP;
  1721.   domain = s1;
  1722.   range = s2;
  1723.   hasAL = FALSE;
  1724.   isDefault = FALSE;
  1725.   domtype = s1.Accepts();
  1726.   rettype = s2.Accepts();
  1727.  
  1728. // Make sure that enough preimage and image objects have been specified.
  1729. // Check that the domain and range dimensions match.
  1730.  
  1731.   if (v1.Length() != domain.Dim() + 2) {
  1732.     errh.ErrorExit(sig, "Incorrect number of objects specified", v1, s1);
  1733.   }
  1734.   if (v2.Length() != range.Dim() + 2) {
  1735.     errh.ErrorExit(sig, "Incorrect number of objects specified", v2, s2);
  1736.   }
  1737.   if (range.Dim() != domain.Dim()) {
  1738.     errh.ErrorExit(sig, "Domain and range dimensions do not match", s1, s2);
  1739.   }
  1740.   if (range.HasRemovedPoints()) {
  1741.     errh.ErrorExit(sig, "Range subset cannot have removed points", range);
  1742.   }
  1743.  
  1744. // Map the objects into the domain and range subsets and use them to start
  1745. // building the transform matrix:
  1746.  
  1747.   int ddim = dspace.MatrixSize();
  1748.   Matrix tempd(v1.Length() - 1, ddim);
  1749.   Matrix unitd(1, ddim);
  1750.   if (!(this->ConvertListUnit(v1, domtype, domain, &tempd, &unitd))) {
  1751.     errh.ErrorExit(sig,
  1752.            "Object cannot be mapped into domain subset", v1, domain);
  1753.   } 
  1754.  
  1755.   int rdim = rspace.MatrixSize();
  1756.   Matrix tempr(v2.Length() - 1, rdim);
  1757.   Matrix unitr(1, rdim);
  1758.   if (!(this->ConvertListUnit(v2, rettype, range, &tempr, &unitr))) {
  1759.     errh.ErrorExit(sig,
  1760.            "Object cannot be mapped into range subset", v2, range);
  1761.   }
  1762.  
  1763. // Convert the domain objects to the domain subset basis representation, then
  1764. // scale the matrix rows.  Do the same for the range:
  1765.  
  1766.   tempd = tempd * domain.FromFull();
  1767.   unitd = unitd * domain.FromFull();
  1768.   if (!(this->ScaleRows(&tempd, unitd))) {
  1769.     errh.ErrorExit(sig, "Domain objects not in general position", v1, s1);
  1770.   } 
  1771.  
  1772.   tempr = tempr * range.FromFull();
  1773.   unitr = unitr * range.FromFull();
  1774.   if (!(this->ScaleRows(&tempr, unitr))) {
  1775.     errh.ErrorExit(sig, "Range objects not in general position", v2, s2);
  1776.   } 
  1777.  
  1778. // Build the transform matrix:
  1779.  
  1780.   t = domain.FromFull() * Inverse(tempd) * tempr * range.ToFull();
  1781.  
  1782. // The invertibility of this transform depends on whether the domain
  1783. // subset has been defined to have removed points.  If it has, the
  1784. // map is not invertible.  Otherwise, calculate the inverse:
  1785.  
  1786.   invertible = !domain.HasRemovedPoints();
  1787.  
  1788.   if (invertible) {
  1789.     invt = range.FromFull() * Inverse(tempr) * tempd * domain.ToFull();
  1790.   }
  1791. }
  1792. // ***********************************************************************
  1793.